package org.gfix.converter;

import java.lang.reflect.Field;
import java.util.HashMap;
import java.util.Map;
import java.util.StringTokenizer;
import java.util.concurrent.ConcurrentHashMap;

import org.gfix.annotation.FixEnumValue;
import org.gfix.binding.FixBindingException;

public class EnumConverter<T extends Enum<?>> implements Converter<T>
{
	
	private static final Map<Class<?>, EnumConverter<?>> cache = new ConcurrentHashMap<Class<?>, EnumConverter<?>>();
	
	@SuppressWarnings("unchecked")
	public static final <S extends Enum<?>> EnumConverter<S> getEnumConverter(Class<S> type) throws FixBindingException
	{
		if(!type.isEnum())
		{
			throw new FixBindingException("Cannot get an enum converter for class "
					+ type.getCanonicalName() + " as it is not an enum");
		}
		EnumConverter<S> convert = (EnumConverter<S>)cache.get(type);
		if(convert == null)
		{
			convert = new EnumConverter<S>(type);
			cache.put(type, convert);
		}
		return convert;
	}
	
	
	private Map<String,T> fixValuesToEnum =  new HashMap<String, T>();
	private Map<T, String> enumValuesToFix =  new HashMap<T, String>();
	
	@SuppressWarnings("unchecked")
	private EnumConverter(Class<?> forType) throws FixBindingException
	{
		try
		{
			for(Field field: forType.getFields())
			{
				FixEnumValue feV = field.getAnnotation(FixEnumValue.class);
				T obj = (T)field.get(null);
	
	
				if(feV != null)
				{
					String outString = feV.fixOutValue();
					StringTokenizer st = new StringTokenizer(feV.fixValue(),",");
					while(st.hasMoreTokens())
					{
						String nextToken = st.nextToken();
						if(outString == null || outString.length() ==0)
						{
							outString = nextToken;
						}
						fixValuesToEnum.put(nextToken, obj);
					}
					enumValuesToFix.put(obj, outString);
				}
				else
				{				
					fixValuesToEnum.put(field.getName(),obj);
					enumValuesToFix.put(obj, field.getName());
				}
			}
			
		} catch (IllegalArgumentException e)
		{
			throw new FixBindingException("",e);
		} catch (IllegalAccessException e) {
			throw new FixBindingException("",e);
		}
	}
	
	@Override
	public T convertFromFix(String contents)
	{
		return (T)fixValuesToEnum.get(contents);
	}

	@Override
	public String convertToFix(T value) {
		return enumValuesToFix.get(value);
	}
	
}
